package border

import "sync"

var wg1 sync.WaitGroup
var wg2 sync.WaitGroup

// BorderBlock 区块数据结构体
type BorderBlock struct {
	NormalizeX2y2 float64
	Normalize2x   float64
	Normalize2y   float64
}

// 消息体
type deliver struct {
	block *BorderBlock
	key   int
}

// 获取区块数据
func createBlock(x, y, length, width int) (block *BorderBlock) {
	block = &BorderBlock{}
	a := float64(x) / float64(length)
	b := float64(y) / float64(width)
	block.NormalizeX2y2 = a*a + b*b
	block.Normalize2x = a + a
	block.Normalize2y = b + b
	return
}

// FindBorder 寻找边界像素
func FindBorder(masks [][]bool) (border []*BorderBlock) {
	width := len(masks)
	length := len(masks[0])
	borderChan := make(chan *deliver, length)
	border = make([]*BorderBlock, 0, length*4)
	wg2.Add(1)
	go func() {
		defer wg2.Done()
		collector(borderChan, length, &border)
	}()

	for i := 0; i < width; i++ {
		wg1.Add(1)
		go func(i int) {
			defer wg1.Done()
			traversalL2R(borderChan, masks, width, length, i)
		}(i)
	}

	for j := 0; j < length; j++ {
		wg1.Add(1)
		go func(j int) {
			defer wg1.Done()
			traversalT2B(borderChan, masks, width, length, j)
		}(j)
	}

	wg1.Wait()
	close(borderChan)
	wg2.Wait()
	return
}

// 左到右遍历
func traversalL2R(borderChan chan *deliver, photoMask [][]bool, width, length, i int) {
	var pre, cur bool
	pre = true
	for j := 0; j <= width; j++ {
		if j == width {
			cur = true
		} else {
			cur = photoMask[i][j]
		}
		if pre && !cur {
			borderChan <- &deliver{key: i*width + j, block: createBlock(j, i, length, width)}
		} else if !pre && cur {
			borderChan <- &deliver{key: i*width + j, block: createBlock(j-1, i, length, width)}
		}
		pre = cur
	}
}

// 上到下遍历
func traversalT2B(borderChan chan *deliver, photoMask [][]bool, width, length, j int) {
	var pre, cur bool
	pre = true
	for i := 0; i <= width; i++ {
		if i == width {
			cur = true
		} else {
			cur = photoMask[i][j]
		}
		if pre && !cur {
			borderChan <- &deliver{key: i*width + j, block: createBlock(j, i, length, width)}
		} else if !pre && cur {
			borderChan <- &deliver{key: i*width + j, block: createBlock(j, i-1, length, width)}
		}
		pre = cur
	}
}

// 收集消息体，过滤多余的数据
func collector(borderChan chan *deliver, length int, border *[]*BorderBlock) {
	borderMap := make(map[int]*BorderBlock, length*4)
	for {
		msg, ok := <-borderChan
		if !ok {
			break
		}
		if borderMap[msg.key] == nil {
			borderMap[msg.key] = msg.block
		}
	}
	for _, v := range borderMap {
		*border = append(*border, v)
	}
}
